<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soulnacos-admin">
      Soul网关源码解析（十九）Nacos数据同步初始化修复-Admin端
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      本篇文章记录一次Nacos数据同步解析中发现问题，并提交PR，成功合并，解决Soul-Admin的Nacos数据同步初始化问题
     </p>
     <h2 id="version">
      代码版本（Version）
     </h2>
     <div class="codehilite">
      <pre><span></span><code>commit b60fb246977ff36fa58ed0a7a9ce22d57dd30323 <span class="o">(</span>upstream/master<span class="o">)</span>
Author: cottom &lt;<span class="m">11937539</span>+cottom@users.noreply.github.com&gt;
Date:   Sun Jan <span class="m">24</span> <span class="m">22</span>:06:34 <span class="m">2021</span> +0800
</code></pre>
     </div>
     <h2 id="problem-description">
      问题简述（Problem Description）
     </h2>
     <p>
      1.在配置后Nacos，并在Nacos中新建对应namespace后，启动Admin，发现在Nacos中并无数据，需要在Admin管理后台页面中收到点击同步数据，数据才会同步到Nacos中
     </p>
     <p>
      2.在上一步同步中，rule相应的Id会建立在Nacos中，但其中并没有数据，导致访问失败
     </p>
     <h2 id="_2">
      问题详情及解决方案探索
     </h2>
     <h3 id="1nacos">
      1.Nacos启动无法初始化问题
     </h3>
     <h4 id="_3">
      相关代码
     </h4>
     <p>
      在同步配置类中，Nacos的配置只是简单启动了Nacos监听，没有类似Zookeeper的还有一个初始化的类，代码大致如下：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="nd">@Configuration</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">DataSyncConfiguration</span> <span class="p">{</span>

    <span class="c1">// 这里只启动了一个监听的，并且在NacosDataChangedListener中，并没有发现任何的初始化操作</span>
    <span class="nd">@Configuration</span>
    <span class="nd">@ConditionalOnProperty</span><span class="p">(</span><span class="n">prefix</span> <span class="o">=</span> <span class="s">"soul.sync.nacos"</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"url"</span><span class="p">)</span>
    <span class="nd">@Import</span><span class="p">(</span><span class="n">NacosConfiguration</span><span class="p">.</span><span class="na">class</span><span class="p">)</span>
    <span class="kd">static</span> <span class="kd">class</span> <span class="nc">NacosListener</span> <span class="p">{</span>

        <span class="nd">@Bean</span>
        <span class="nd">@ConditionalOnMissingBean</span><span class="p">(</span><span class="n">NacosDataChangedListener</span><span class="p">.</span><span class="na">class</span><span class="p">)</span>
        <span class="kd">public</span> <span class="n">DataChangedListener</span> <span class="nf">nacosDataChangedListener</span><span class="p">(</span><span class="kd">final</span> <span class="n">ConfigService</span> <span class="n">configService</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">new</span> <span class="n">NacosDataChangedListener</span><span class="p">(</span><span class="n">configService</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h4 id="_4">
      解决方案探索
     </h4>
     <p>
      可以解决Zookeeper的代码，新建一个初始化数据的类，判断其数据节点是否存在，如果不存在，则进行从数据库中读取所有数据，发布事件，触发Nacos的初始化
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">DataSyncConfiguration</span> <span class="p">{</span>
    <span class="nd">@Configuration</span>
    <span class="nd">@ConditionalOnProperty</span><span class="p">(</span><span class="n">prefix</span> <span class="o">=</span> <span class="s">"soul.sync.zookeeper"</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="s">"url"</span><span class="p">)</span>
    <span class="nd">@Import</span><span class="p">(</span><span class="n">ZookeeperConfiguration</span><span class="p">.</span><span class="na">class</span><span class="p">)</span>
    <span class="kd">static</span> <span class="kd">class</span> <span class="nc">ZookeeperListener</span> <span class="p">{</span>

        <span class="nd">@Bean</span>
        <span class="nd">@ConditionalOnMissingBean</span><span class="p">(</span><span class="n">ZookeeperDataChangedListener</span><span class="p">.</span><span class="na">class</span><span class="p">)</span>
        <span class="kd">public</span> <span class="n">DataChangedListener</span> <span class="nf">zookeeperDataChangedListener</span><span class="p">(</span><span class="kd">final</span> <span class="n">ZkClient</span> <span class="n">zkClient</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">new</span> <span class="n">ZookeeperDataChangedListener</span><span class="p">(</span><span class="n">zkClient</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="nd">@Bean</span>
        <span class="nd">@ConditionalOnMissingBean</span><span class="p">(</span><span class="n">ZookeeperDataInit</span><span class="p">.</span><span class="na">class</span><span class="p">)</span>
        <span class="kd">public</span> <span class="n">ZookeeperDataInit</span> <span class="nf">zookeeperDataInit</span><span class="p">(</span><span class="kd">final</span> <span class="n">ZkClient</span> <span class="n">zkClient</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SyncDataService</span> <span class="n">syncDataService</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">return</span> <span class="k">new</span> <span class="n">ZookeeperDataInit</span><span class="p">(</span><span class="n">zkClient</span><span class="p">,</span> <span class="n">syncDataService</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      初步写了一个Nacos初始化触发的类，模仿的ZookeeperDataInit,在run函数中，首先判断插件、元数据、认证数据的Id数据是否存在，如果不存在，则想Zookeeper一样触发同步所有数据的事件
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">NacosDataInit</span> <span class="kd">implements</span> <span class="n">CommandLineRunner</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">GROUP</span> <span class="o">=</span> <span class="s">"DEFAULT_GROUP"</span><span class="p">;</span>

    <span class="kd">private</span> <span class="kd">final</span> <span class="n">ConfigService</span> <span class="n">configService</span><span class="p">;</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="n">SyncDataService</span> <span class="n">syncDataService</span><span class="p">;</span>

    <span class="kd">public</span> <span class="nf">NacosDataInit</span><span class="p">(</span><span class="kd">final</span> <span class="n">ConfigService</span> <span class="n">configService</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SyncDataService</span> <span class="n">syncDataService</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="na">configService</span> <span class="o">=</span> <span class="n">configService</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="na">syncDataService</span> <span class="o">=</span> <span class="n">syncDataService</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="p">(</span><span class="n">String</span><span class="p">...</span> <span class="n">args</span><span class="p">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">pluginId</span> <span class="o">=</span> <span class="n">NacosDataIdConstants</span><span class="p">.</span><span class="na">PLUGIN_DATA_ID</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">authId</span> <span class="o">=</span> <span class="n">NacosDataIdConstants</span><span class="p">.</span><span class="na">AUTH_DATA_ID</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">metaDataId</span> <span class="o">=</span> <span class="n">NacosDataIdConstants</span><span class="p">.</span><span class="na">META_DATA_ID</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">isExists</span><span class="p">(</span><span class="n">pluginId</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">isExists</span><span class="p">(</span><span class="n">authId</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">isExists</span><span class="p">(</span><span class="n">metaDataId</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">syncDataService</span><span class="p">.</span><span class="na">syncAll</span><span class="p">(</span><span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">REFRESH</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="nd">@SneakyThrows</span>
    <span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">isExists</span><span class="p">(</span><span class="n">String</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">configService</span><span class="p">.</span><span class="na">getConfig</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">GROUP</span><span class="p">,</span> <span class="mi">3000</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      经过初步测试，上面的初始化类，在Nacos为空时，重启Admin，能初步同步数据到Nacos中
     </p>
     <p>
      但还是存在下面的第二个问题：rule规则为空
     </p>
     <h3 id="2rule">
      2.同步插件数据后，rule规则没有进行同步，仍为空
     </h3>
     <h4 id="_5">
      相关代码
     </h4>
     <p>
      如下代码所示，在进行插件同步（触发条件为在Admin管理后台界面点击同步自定义xxx插件），根据代码大意：会进行触发插件数据的更新和其选择器和规则，但调试发现，并不能成功更新规则数据，原因是下一段代码：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">SyncDataServiceImpl</span> <span class="kd">implements</span> <span class="n">SyncDataService</span> <span class="p">{</span>

    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">syncPluginData</span><span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">pluginId</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">PluginVO</span> <span class="n">pluginVO</span> <span class="o">=</span> <span class="n">pluginService</span><span class="p">.</span><span class="na">findById</span><span class="p">(</span><span class="n">pluginId</span><span class="p">);</span>
        <span class="c1">// 同步插件</span>
        <span class="n">eventPublisher</span><span class="p">.</span><span class="na">publishEvent</span><span class="p">(</span><span class="k">new</span> <span class="n">DataChangedEvent</span><span class="p">(</span><span class="n">ConfigGroupEnum</span><span class="p">.</span><span class="na">PLUGIN</span><span class="p">,</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">UPDATE</span><span class="p">,</span>
                <span class="n">Collections</span><span class="p">.</span><span class="na">singletonList</span><span class="p">(</span><span class="n">PluginTransfer</span><span class="p">.</span><span class="na">INSTANCE</span><span class="p">.</span><span class="na">mapDataTOVO</span><span class="p">(</span><span class="n">pluginVO</span><span class="p">))));</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">SelectorData</span><span class="o">&gt;</span> <span class="n">selectorDataList</span> <span class="o">=</span> <span class="n">selectorService</span><span class="p">.</span><span class="na">findByPluginId</span><span class="p">(</span><span class="n">pluginId</span><span class="p">);</span>
        <span class="c1">// 同步选择器</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">CollectionUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">selectorDataList</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">eventPublisher</span><span class="p">.</span><span class="na">publishEvent</span><span class="p">(</span><span class="k">new</span> <span class="n">DataChangedEvent</span><span class="p">(</span><span class="n">ConfigGroupEnum</span><span class="p">.</span><span class="na">SELECTOR</span><span class="p">,</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">REFRESH</span><span class="p">,</span> <span class="n">selectorDataList</span><span class="p">));</span>
            <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">allRuleDataList</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span>
            <span class="k">for</span> <span class="p">(</span><span class="n">SelectorData</span> <span class="n">selectData</span> <span class="p">:</span> <span class="n">selectorDataList</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">ruleDataList</span> <span class="o">=</span> <span class="n">ruleService</span><span class="p">.</span><span class="na">findBySelectorId</span><span class="p">(</span><span class="n">selectData</span><span class="p">.</span><span class="na">getId</span><span class="p">());</span>
                <span class="n">allRuleDataList</span><span class="p">.</span><span class="na">addAll</span><span class="p">(</span><span class="n">ruleDataList</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="c1">// 同步规则</span>
            <span class="n">eventPublisher</span><span class="p">.</span><span class="na">publishEvent</span><span class="p">(</span><span class="k">new</span> <span class="n">DataChangedEvent</span><span class="p">(</span><span class="n">ConfigGroupEnum</span><span class="p">.</span><span class="na">RULE</span><span class="p">,</span> <span class="n">DataEventTypeEnum</span><span class="p">.</span><span class="na">REFRESH</span><span class="p">,</span> <span class="n">allRuleDataList</span><span class="p">));</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      从上面的函数事件发布后，进行规则的更新，来到下面的Nacos规则数据更新代码
     </p>
     <p>
      事件为REFRESH，在其处理逻辑中，我们发现其并能添加进去新的规则：因为ls的取值逻辑会一直为空，本身RULE_MAP就是为空的，取不到值
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">onRuleChanged</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">changed</span><span class="p">,</span> <span class="kd">final</span> <span class="n">DataEventTypeEnum</span> <span class="n">eventType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">updateRuleMap</span><span class="p">(</span><span class="n">getConfig</span><span class="p">(</span><span class="n">RULE_DATA_ID</span><span class="p">));</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">eventType</span><span class="p">)</span> <span class="p">{</span>
                <span class="p">.......</span>
            <span class="k">case</span> <span class="n">REFRESH</span><span class="p">:</span>
            <span class="c1">// 在Zookeeper的初始化触发MYSELF，那Nacos应该也是一样</span>
            <span class="c1">// 在初始化的时候，下面的ls中始终为空，rule无法添加进去</span>
            <span class="k">case</span> <span class="n">MYSELF</span><span class="p">:</span>
                <span class="n">Set</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="n">set</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HashSet</span><span class="o">&lt;&gt;</span><span class="p">(</span><span class="n">RULE_MAP</span><span class="p">.</span><span class="na">keySet</span><span class="p">());</span>
                <span class="n">changed</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">rule</span> <span class="o">-&gt;</span> <span class="p">{</span>
                    <span class="n">set</span><span class="p">.</span><span class="na">remove</span><span class="p">(</span><span class="n">rule</span><span class="p">.</span><span class="na">getSelectorId</span><span class="p">());</span>
                    <span class="c1">// 始终为空</span>
                    <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">ls</span> <span class="o">=</span> <span class="n">RULE_MAP</span>
                            <span class="p">.</span><span class="na">getOrDefault</span><span class="p">(</span><span class="n">rule</span><span class="p">.</span><span class="na">getSelectorId</span><span class="p">(),</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">())</span>
                            <span class="p">.</span><span class="na">stream</span><span class="p">()</span>
                            <span class="p">.</span><span class="na">sorted</span><span class="p">(</span><span class="n">RULE_DATA_COMPARATOR</span><span class="p">)</span>
                            <span class="p">.</span><span class="na">collect</span><span class="p">(</span><span class="n">Collectors</span><span class="p">.</span><span class="na">toList</span><span class="p">());</span>
                    <span class="c1">// 可以直接加进去</span>
                    <span class="n">ls</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">rule</span><span class="p">);</span>
                    <span class="n">RULE_MAP</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">rule</span><span class="p">.</span><span class="na">getSelectorId</span><span class="p">(),</span> <span class="n">ls</span><span class="p">);</span>
                <span class="p">});</span>
                <span class="n">RULE_MAP</span><span class="p">.</span><span class="na">keySet</span><span class="p">().</span><span class="na">removeAll</span><span class="p">(</span><span class="n">set</span><span class="p">);</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">default</span><span class="p">:</span>
                <span class="p">......</span>
                <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">publishConfig</span><span class="p">(</span><span class="n">RULE_DATA_ID</span><span class="p">,</span> <span class="n">RULE_MAP</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <h4 id="_6">
      解决方案探索
     </h4>
     <p>
      在REFRESH的逻辑处理中出现了错误，REFRESH的处理逻辑参照zookeeper应该是：
     </p>
     <ul>
      <li>
       1.清空本地的缓存数据
      </li>
      <li>
       2.添加传入的新的数据
      </li>
     </ul>
     <p>
      但在下面原理的逻辑代码中，逻辑不是很清晰，将起来也比较费劲，我们直接修改为下面的代码：
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">onRuleChanged</span><span class="p">(</span><span class="kd">final</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">changed</span><span class="p">,</span> <span class="kd">final</span> <span class="n">DataEventTypeEnum</span> <span class="n">eventType</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">updateRuleMap</span><span class="p">(</span><span class="n">getConfig</span><span class="p">(</span><span class="n">RULE_DATA_ID</span><span class="p">));</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">eventType</span><span class="p">)</span> <span class="p">{</span>
                <span class="p">.......</span>
            <span class="k">case</span> <span class="n">REFRESH</span><span class="p">:</span>
            <span class="k">case</span> <span class="n">MYSELF</span><span class="p">:</span>
                <span class="c1">// 清空本地缓存数据</span>
                <span class="n">SELECTOR_MAP</span><span class="p">.</span><span class="na">keySet</span><span class="p">().</span><span class="na">removeAll</span><span class="p">(</span><span class="n">SELECTOR_MAP</span><span class="p">.</span><span class="na">keySet</span><span class="p">());</span>
                <span class="n">changed</span><span class="p">.</span><span class="na">forEach</span><span class="p">(</span><span class="n">rule</span> <span class="o">-&gt;</span> <span class="p">{</span>
                    <span class="c1">// 根据当前rule对应的selectorid，得到rule所在的列表</span>
                    <span class="c1">// 如果为空，则新建一个列表</span>
                    <span class="c1">// 如果之前有，那取出来</span>
                    <span class="n">List</span><span class="o">&lt;</span><span class="n">RuleData</span><span class="o">&gt;</span> <span class="n">ls</span> <span class="o">=</span> <span class="n">RULE_MAP</span>
                            <span class="p">.</span><span class="na">getOrDefault</span><span class="p">(</span><span class="n">rule</span><span class="p">.</span><span class="na">getSelectorId</span><span class="p">(),</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">())</span>
                            <span class="p">.</span><span class="na">stream</span><span class="p">()</span>
                            <span class="p">.</span><span class="na">sorted</span><span class="p">(</span><span class="n">RULE_DATA_COMPARATOR</span><span class="p">)</span>
                            <span class="p">.</span><span class="na">collect</span><span class="p">(</span><span class="n">Collectors</span><span class="p">.</span><span class="na">toList</span><span class="p">());</span>
                    <span class="c1">// 将新的规则添加到selector的列表中</span>
                    <span class="n">ls</span><span class="p">.</span><span class="na">add</span><span class="p">(</span><span class="n">rule</span><span class="p">);</span>
                    <span class="n">RULE_MAP</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="n">rule</span><span class="p">.</span><span class="na">getSelectorId</span><span class="p">(),</span> <span class="n">ls</span><span class="p">);</span>
                <span class="p">});</span>
                <span class="k">break</span><span class="p">;</span>
            <span class="k">default</span><span class="p">:</span>
                <span class="p">......</span>
                <span class="k">break</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="n">publishConfig</span><span class="p">(</span><span class="n">RULE_DATA_ID</span><span class="p">,</span> <span class="n">RULE_MAP</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre>
     </div>
     <p>
      核心逻辑就是先清空缓存；然后逐个将rule添加到对应的selector的列表中
     </p>
     <p>
      经过初步测试，能解决初始化的时候rule没有数据和同步自定义插件没有更新rule的问题，并且请求访问正常
     </p>
     <h2 id="_7">
      总结
     </h2>
     <p>
      在前面的分析中，我们就遇到了Nacos的问题，然后我们先解析了Admin的Zookeeper的同步数据逻辑，以此来对应上我们这次的Nacos同步逻辑。并顺利的找到其相应的bug，并成功修改提交PR，成功合并！
     </p>
     <p>
      运用所学，解决了一个问题，真滴开心！
     </p>
     <h2 id="_8">
      参考链接
     </h2>
     <ul>
      <li>
       <a href="https://nacos.io/zh-cn/docs/sdk.html">
        Nacos Java SDK
       </a>
      </li>
     </ul>
     <h2 id="soul">
      Soul网关源码分析文章列表
     </h2>
     <h3 id="_9">
      掘金
     </h3>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码阅读（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码阅读（二）代码初步运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码阅读（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码阅读（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码阅读（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码阅读（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919348164944232455/">
        Soul网关源码阅读（七）限流插件初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919774553241550855/">
        Soul网关源码阅读（八）路由匹配初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920074307590684685/">
        Soul网关源码阅读（九）插件配置加载初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920142348617777166">
        Soul网关源码阅读（十）自定义简单插件编写
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596034171174925">
        Soul网关源码阅读（十一）请求处理小结
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596173925384206">
        Soul网关源码阅读（十二）数据同步初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596028505178125">
        Soul网关源码阅读（十三）Websocket同步数据-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920597298674302983">
        Soul网关源码阅读（十四）HTTP数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920764643967238151">
        Soul网关源码阅读（十五）Zookeeper数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921170233868845064">
        Soul网关源码阅读（十六）Nacos数据同步示例运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921325882753695757/">
        Soul网关源码阅读（十七）Nacos数据同步解析-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921495273122463751/">
        Soul网关源码阅读（十八）Zookeeper数据同步初探-Admin端
       </a>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
